
#import "Common.h"
#import "Sprite.h"

@implementation Sprite

@synthesize texture;
@synthesize	pos,size,hotspot;
@synthesize rotateAngle,scale;
@synthesize textCoordLeftTop,textCoordRightBottom;
@synthesize hidden;
@synthesize play;

@dynamic	blink;
@synthesize blinkFreq;

@synthesize	currentAnimation=currentAnim;
@synthesize animationsCount=animsCount;

@dynamic isLastFrame;

@synthesize loop;

static Vector3 defaultHotspot;
static Vector3 defaultSize;
static Vector3 defaultFrameSize;

+(void)setDefaultFrameSize:(Vector3)size
{
	defaultFrameSize = size;
}

+(void)setDefaultHotspot:(Vector3)hotspot
{
	defaultHotspot = hotspot;
}

+(void)setDefaultSize:(Vector3)size
{
	defaultSize = size;
}

+(Vector3)defaultHotspot
{
	return defaultHotspot;
}

+(Vector3)defaultSize
{
	return defaultSize;
}

+(Vector3)defaultFrameSize
{
	return defaultFrameSize;
}

-(id) initWithFileNamed:(NSString*) filename
{
	if(self = [super init])
	{
		play = YES;
		
		blink = NO;
		blinkFreq = 1;
		
		texture = (Texture *)[[ResourceManager instance] loadResource:[Texture class] name:filename];

		hotspot = Vector3Make(0, 0, 0);
		
		size = Vector3Make(texture.width,texture.height,0);
		
		//textCoord[0] = Vector3Make(0, 0, 0);
		textCoordLeftTop = Vector3Make(0, 0, 0);
		
		//textCoord[1] = Vector3Make(1, 1, 0);
		textCoordRightBottom = Vector3Make(1, 1, 0);
		
		scale = 1.0f;
		
		rotateAngle = 0;
		
		loop = YES;
		
		[self updateWithTime:0 DeltaTime:0];
	}
	
	return self;
}

-(id) initWithFileName:(NSString*)filename FramesCount:(int)framesCount FramesPerLine:(int)framesPerLine
{
	//Vector3 frameSize = Vector3Make(64,64,0);
	Vector3 frameSize = defaultFrameSize;
	
	if(self=[self initWithFileNamed:filename])
	{
		float u,v;
		float uWidth = frameSize.x/texture.width;
		float vHeight = frameSize.y/texture.height;
		
		int row,col;
		
		loop = YES;

		animsCount = 1;
		animsArray = malloc(animsCount*sizeof(SpriteAnimDef));
		
		for(int i=0;i<animsCount;i++)
		{
			animsArray[i].framesCount = framesCount;
			
			// Alloc frames and copy it from animDefArray
			animsArray[i].framesArray = malloc(animsArray[i].framesCount*sizeof(SpriteFrameDef));
			for(int f=0;f<animsArray[i].framesCount;f++)
			{
				row = f/framesPerLine;
				col = f%framesPerLine;
				
				u = col*frameSize.x/texture.width;
				v = row*frameSize.y/texture.height;
				
				//animsArray[i].framesArray[f].size = Vector3Make(32,32,0);
				animsArray[i].framesArray[f].size = defaultSize;
				//animsArray[i].framesArray[f].hotspot = Vector3Make(16, 0, 32);
				animsArray[i].framesArray[f].hotspot = defaultHotspot;
				animsArray[i].framesArray[f].textCoord[0] = Vector3Make(u, v, 0);
				animsArray[i].framesArray[f].textCoord[1] = Vector3Make(u+uWidth, v+vHeight, 0);
			}
			
			animsArray[i].frameFreq = 1.0f/45.0f;
			animsArray[i].loop		= YES;
			animsArray[i].reverse	= NO;
		}
		
		[self setAnimation:0];
		[self updateWithTime:0 DeltaTime:0];
		
		
		for(int i=0;i<framesCount;i++)
		{		
			
		}
	}
	
	return self;
}

-(id) initWithAnimDefArray:(SpriteAnimDef**)animDefArray TextureFileName:(NSString*)filename
{
	if(self=[self initWithFileNamed:filename])
	{
		play = YES;
		loop = YES;

		animsCount=0;
		
		while(animDefArray[animsCount]) animsCount++;

		animsArray = malloc(animsCount*sizeof(SpriteAnimDef));
		
		for(int i=0;i<animsCount;i++)
		{
			//int framesCount = 0;
			//while(animDefArray[animsCount]->framesArray[framesCount]) framesCount++;
			//animsArray[i].framesCount = framesCount;
			animsArray[i].framesCount = animDefArray[i]->framesCount;
			
			// Alloc frames and copy it from animDefArray
			animsArray[i].framesArray = malloc(animsArray[i].framesCount*sizeof(SpriteFrameDef));
			for(int f=0;f<animsArray[i].framesCount;f++)
			{
				animsArray[i].framesArray[f] = animDefArray[i]->framesArray[f];
			}
			
			animsArray[i].frameFreq = animDefArray[i]->frameFreq;
			animsArray[i].loop		= animDefArray[i]->loop;
			animsArray[i].reverse	= animDefArray[i]->reverse;
		}
		
		[self setAnimation:0];
		[self updateWithTime:0 DeltaTime:0];
	}
	
	return self;
}

-(void) dealloc
{
	for(int i=0;i<animsCount;i++)
	{
		if(animsArray[i].framesArray)
			free(animsArray[i].framesArray);
		
		free(animsArray);
	}
		
	if(texture)
	{
		[[ResourceManager instance] unloadResource:texture];
		[texture release];
	}
	
	[super dealloc];
}


#pragma mark 
#pragma mark Render Support

// For Z-order sort
-(float) getZValue
{
	return pos.z - hotspot.z;
}

// Number of drawed vertexes
-(int) renderSelfToBufferVertex:(Vector3*)vertexBuffer Color:(ColorRGBA*)colorBuffer TextCoord:(float*)textCoordBuffer
{
	if(hidden || blinkHide)
		return 0;
	
	[self updateWithTime:0 DeltaTime:0];
	
	static Vector3 leftTopPos,rightTopPos,leftBottomPos,rightBottomPos;
	static Vector3 leftTopText,rightTopText,leftBottomText,rightBottomText;
	
	Vector3 hotspotedPos;
	Vector3 scaledHotspot;
	Vector3 scaledSize;
	
	vec3MulFloat(&hotspot,scale,&scaledHotspot);
	vec3Sub(&pos,&scaledHotspot,&hotspotedPos);
	
//	hotspotedPos.x += size.x/2;
//	hotspotedPos.y += size.y/2;
	
	vec3MulFloat(&size, scale, &scaledSize);
	
	Vector3	scaledSizeHorz;
	Vector3	scaledSizeVert;
	// Rotate sprite 
	if(rotateAngle!=0)
	{
		scaledSizeHorz.x = scaledSize.x * cosf(rotateAngle);
		scaledSizeHorz.y = scaledSize.x * sinf(rotateAngle);
		
		scaledSizeVert.x = scaledSize.y * cosf(rotateAngle);
		scaledSizeVert.y = scaledSize.y * sinf(rotateAngle);
	}
	
	// Pos

//	leftTopPos		=  Vector3Make(hotspotedPos.x - scaledSize.x, hotspotedPos.y- scaledSize.y, hotspotedPos.z);
//	rightTopPos		=  Vector3Make(hotspotedPos.x + scaledSize.x, hotspotedPos.y- scaledSize.y, hotspotedPos.z);
//	leftBottomPos	=  Vector3Make(hotspotedPos.x - scaledSize.x, hotspotedPos.y+ scaledSize.y, hotspotedPos.z);
//	rightBottomPos	=  Vector3Make(hotspotedPos.x + scaledSize.x, hotspotedPos.y+ scaledSize.y, hotspotedPos.z);

	leftTopPos		=  hotspotedPos;
	rightTopPos		=  Vector3Make(hotspotedPos.x + scaledSize.x, hotspotedPos.y, hotspotedPos.z);
	leftBottomPos	=  Vector3Make(hotspotedPos.x, hotspotedPos.y+ scaledSize.y, hotspotedPos.z);
	rightBottomPos	=  Vector3Make(hotspotedPos.x + scaledSize.x, hotspotedPos.y+ scaledSize.y, hotspotedPos.z);
	
	vertexBuffer[0] = leftTopPos;
	vertexBuffer[1] = rightTopPos;
	vertexBuffer[2] = rightBottomPos;
	
	vertexBuffer[3] = leftTopPos;
	vertexBuffer[4] = rightBottomPos;
	vertexBuffer[5] = leftBottomPos;
	
	// Texture Coords 
	
	//leftTopText		= textCoord[0];
	leftTopText		= textCoordLeftTop;
	rightTopText	= Vector3Make(textCoordRightBottom.x, textCoordLeftTop.y, 0);
	leftBottomText	= Vector3Make(textCoordLeftTop.x, textCoordRightBottom.y, 0);;
	rightBottomText = textCoordRightBottom;
	
	textCoordBuffer[0] = leftTopText.x;
	textCoordBuffer[1] = leftTopText.y;

	textCoordBuffer[2] = rightTopText.x;
	textCoordBuffer[3] = rightTopText.y;

	textCoordBuffer[4] = rightBottomText.x;
	textCoordBuffer[5] = rightBottomText.y;

	textCoordBuffer[6] = leftTopText.x;
	textCoordBuffer[7] = leftTopText.y;
	
	textCoordBuffer[8] = rightBottomText.x;
	textCoordBuffer[9] = rightBottomText.y;
	
	textCoordBuffer[10] = leftBottomText.x;
	textCoordBuffer[11] = leftBottomText.y;
	
	
	// Vertex Colors
	for(int i=0;i<6;i++)
		colorBuffer[i] = ColorRGBAMake(1, 0, 1, 1);
	
	return 6;
}

// Texture to create texture sorted list, for less render states changes
-(Texture*) getTexture
{
	return texture;	
}

-(void) updateWithTime:(float)time DeltaTime:(float)delta
{
	/*
	 *	Update blink
	 */
	if(blink)
	{
		blinkTimer -= delta;
		
		if(blinkTimer < 0)
		{
			blinkTimer = 1.0/(2.0*blinkFreq) - (-blinkTimer);
			
			blinkHide = !blinkHide;
		}
	}
	
	if(!animsArray)
		return ;
	
	// Update current frame 

	SpriteAnimDef	*currentAnimDef = &animsArray[currentAnim];
	

	/*
	 *	Update currentFrame
	 */
	if(	play == YES)
		frameTime -= delta;

	if(frameTime <=0)	// Time to switch to next frame
	{
		if(currentAnimDef->reverse)
		{
			if(currentFrame>0)
				currentFrame--;
			else
			{
				currentFrame = (currentAnimDef->loop && loop) ? currentAnimDef->framesCount-1 : 0;
			}
		}
		else
		{
			if(currentFrame<currentAnimDef->framesCount-1)
				currentFrame++;
			else
				currentFrame = (currentAnimDef->loop && loop) ? 0 : currentAnimDef->framesCount-1;
		}			

		// Dont trunc negative time delta than change sprite frame
		frameTime = currentAnimDef->frameFreq - (-frameTime);
	}

	/*
	 *	Copy current anim frame to sprite
	 */
	SpriteFrameDef	*currentFrameDef = &currentAnimDef->framesArray[currentFrame];

	self->size			= currentFrameDef->size;
	self->hotspot		= currentFrameDef->hotspot;
	self->textCoordLeftTop	= currentFrameDef->textCoord[0];
	self->textCoordRightBottom	= currentFrameDef->textCoord[1];
}

-(void) setAnimation:(int) animNum
{
	assert(animNum < animsCount);
	
	currentFrame = 0;
	currentAnim = animNum;
	
	frameTime = animsArray[currentAnim].frameFreq;
	
	[self updateWithTime:0 DeltaTime:0];
}

-(void) setFrame:(int) frameNum
{
	assert(frameNum < animsArray[currentAnim].framesCount);
	
	frameTime = animsArray[currentAnim].frameFreq;

	currentFrame = frameNum;
	
	[self updateWithTime:0 DeltaTime:0];
}

-(void) setTextCoordLeftTop:(Vector3)leftTop RightBottom:(Vector3)rightBottom
{
	textCoordLeftTop = leftTop;
	textCoordRightBottom = rightBottom;
}

-(void) setTextCoordPixelsLeftTop:(Vector3)leftTop RightBottom:(Vector3)rightBottom
{
	leftTop.x /= texture.width;
	leftTop.y /= texture.height;

	rightBottom.x /= texture.width;
	rightBottom.y /= texture.height;
	
	[self setTextCoordLeftTop:leftTop RightBottom:rightBottom];
}

-(void) setBlink:(BOOL) isBlink
{
	if(blink!=isBlink)
	{
		blink = isBlink;
		blinkTimer = 1.0/(2.0*blinkFreq);
		blinkHide = NO;
	}
}

-(BOOL) isLastFrame
{
	return currentFrame == animsArray[currentAnim].framesCount-1;
}

@end
